home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / vm / vmCOW.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  32.6 KB  |  1,196 lines

  1. /* 
  2.  * vmCOW.c --
  3.  *
  4.  * This file contains routines that implement copy-on-write.
  5.  *
  6.  * Copy-on-write (COW) is implemented by linking all related instances of a
  7.  * segment in a list. "Related instances" means all segments related by a fork
  8.  * of some initial segment, including children, grandchildren, etc.  Each page
  9.  * in each related segment is marked either OK (meaning the page is no longer
  10.  * involved in any COW activity), COW or COR (meaning it's copy-on-reference).
  11.  * COR pages have no associated backing store or main-memory contents yet, but
  12.  * the PTE for each COR page names the segment from which this page is to be 
  13.  * copied by setting the page frame number equal to the segment number of the
  14.  * source of the page.  Pages are marked COW and COR through the use of the
  15.  * bits in the PTE.
  16.  *
  17.  * When a COR page is referenced, the routine VmCOR is called.  The source of
  18.  * the page is found through the page frame number and a copy of the page is 
  19.  * made.  The source is left COW.  When a COW page (call it A) is written then
  20.  * the routine VmCOW is called.  Another page (call it B) is found by
  21.  * traversing the list of segments.  Page A is then copied to page B and A is
  22.  * marked OK (no longer COW).  If there are any other pages that were COR off 
  23.  * of A besides B, then B is marked COW and each of the other pages is marked
  24.  * COR off of B.  Otherwise B is marked OK.
  25.  *
  26.  * During a fork the routine VmSegFork is called.  The newly created segment
  27.  * is added to the list of related segments which contains the new segment's
  28.  * parent.  For each page that is COR in the parent, the child is marked COR
  29.  * off of the same page.  For each page that is marked COW in the parent,
  30.  * the child is marked COR off of the parent.  For each parent page that is
  31.  * resident or on swap space, the child is marked COR off of the parent.
  32.  * All other pages (zero fill or demand load from the file system) are set up
  33.  * to be the same for the child.
  34.  *
  35.  * When a segment or a portion of a segment which contains COW pages is
  36.  * deleted then all of the COW pages must be duplicated.  This is done
  37.  * by calling the routine VmCOWDeleteFromSeg.  For each COW
  38.  * page (call it A), if there is segment which is COR off of A, then A is
  39.  * copied to B.  If A is resident this is done by remapping the page in A
  40.  * onto B.  Otherwise the swap space behind A is copied to B's backing store.
  41.  * 
  42.  * When a segment is migrated, a copy of it has to be made.  This is done by
  43.  * calling the routine VmCOWCopy.  For each COR page a COR fault is simulated.
  44.  * For each COW page a COW fault is simulated.
  45.  *
  46.  * SYNCHRONIZATION
  47.  *
  48.  * The routines in this file are designed to be called by routines in 
  49.  * vmPage.c and vmSeg.c.  Whenever any of these routines are called  it is
  50.  * assumed that the page tables for the segment have had their user count
  51.  * incremented so that it is safe to grab a pointer to the page tables outside.
  52.  * of the monitor lock. Also only one operation can occur to a
  53.  * copy-on-write chain at one time.  This is assured by embedding a lock into 
  54.  * a common data structure that all  segments in a copy-on-write chain 
  55.  * reference (VmCOWInfo).  Since only one operation can happen at a time and 
  56.  * the pages tables are safe this greatly simplifies the code.
  57.  *
  58.  * CLEANUP
  59.  *
  60.  * There are several cases in which the COW chain must be cleaned up.  The
  61.  * cases and how they are handled are:
  62.  *
  63.  * 1) After a COW or a COR fault occurs for page A, there may be no more pages
  64.  *    that are COR off of A.  However, there is no way of knowing this without
  65.  *    searching the entire chain.  In this case A is left COW and then if
  66.  *    a subsequent COW fault occurs on A, A will be marked OK.
  67.  * 2) After a COW or COR fault there may be no more COR or COW pages in the
  68.  *    faulting segment.  In this case the segment is deleted from the list.
  69.  * 3) After a COR fault, COW fault, or a segment is deleted there may be
  70.  *    only one segement left in the list.  In this case all pages are marked
  71.  *    OK in the segment, the segment is removed from the chain and the
  72.  *    VmCOWInfo struct is freed.
  73.  *
  74.  * Copyright (C) 1985 Regents of the University of California
  75.  * All rights reserved.
  76.  */
  77.  
  78. #ifndef lint
  79. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/vm/vmCOW.c,v 9.7 91/09/10 18:29:26 rab Exp $ SPRITE (Berkeley)";
  80. #endif not lint
  81.  
  82. #include <sprite.h>
  83. #include <vmStat.h>
  84. #include <vm.h>
  85. #include <vmInt.h>
  86. #include <user/vm.h>
  87. #include <sync.h>
  88. #include <dbg.h>
  89. #include <list.h>
  90. #include <lock.h>
  91. #include <sys.h>
  92. #include <stdlib.h>
  93. #include <stdio.h>
  94. #include <bstring.h>
  95.  
  96. #ifdef sun4
  97. /*
  98.  * Due to the cache flushing necessitated by all the mapping games, COW
  99.  * seems to be a lose on the sun4 right now.
  100.  */
  101. Boolean    vm_CanCOW = FALSE;
  102. #else
  103. Boolean    vm_CanCOW = TRUE;
  104. #endif /* sun4 */
  105.  
  106. static void DoFork _ARGS_((register Vm_Segment *srcSegPtr,
  107.     register Vm_Segment *destSegPtr));
  108. static void GiveAwayPage _ARGS_((register Vm_Segment *srcSegPtr, int virtPage,
  109.     register Vm_PTE *srcPTEPtr, register Vm_Segment *destSegPtr,
  110.     Boolean others));
  111. static void ReleaseCOW  _ARGS_((Vm_PTE *ptePtr));
  112. static Boolean COWStart _ARGS_((register Vm_Segment *segPtr,
  113.     register VmCOWInfo **cowInfoPtrPtr));
  114. static Vm_Segment *FindNewMasterSeg _ARGS_((register Vm_Segment *segPtr,
  115.     int page, Boolean *othersPtr));
  116. static Boolean IsResident _ARGS_((Vm_PTE *ptePtr));
  117. static void COWEnd _ARGS_((register Vm_Segment *segPtr,
  118.     VmCOWInfo **cowInfoPtrPtr));
  119. static void SetPTE _ARGS_((Vm_VirtAddr *virtAddrPtr, Vm_PTE pte));
  120. static void CopyPage _ARGS_((unsigned int srcPF, unsigned int destPF));
  121. static ReturnStatus COR _ARGS_((register Vm_VirtAddr *virtAddrPtr,
  122.     register Vm_PTE *ptePtr));
  123. static void COW _ARGS_((register Vm_VirtAddr *virtAddrPtr,
  124.     register Vm_PTE *ptePtr, Boolean isResident, Boolean deletePage));
  125. static unsigned int GetMasterPF();
  126. static void SeeIfLastCOR _ARGS_((register Vm_Segment *mastSegPtr,
  127.     int page));
  128.  
  129.  
  130. /*
  131.  *----------------------------------------------------------------------
  132.  *
  133.  * VmSegFork --
  134.  *
  135.  *    Make a copy-on-reference copy of the given segment.  It is assumed
  136.  *    that this routine is called with the source segment's page table
  137.  *    in use count incremented.
  138.  *
  139.  * Results:
  140.  *    None.
  141.  *
  142.  * Side effects:
  143.  *    Memory may be allocated for COW info struct.
  144.  *
  145.  *----------------------------------------------------------------------
  146.  */
  147. void
  148. VmSegFork(srcSegPtr, destSegPtr)
  149.     Vm_Segment    *srcSegPtr;
  150.     Vm_Segment    *destSegPtr;
  151. {
  152.     VmCOWInfo    *cowInfoPtr;
  153.  
  154.     cowInfoPtr = (VmCOWInfo *)malloc(sizeof(VmCOWInfo));
  155.     (void)COWStart(srcSegPtr, &cowInfoPtr);
  156.     if (cowInfoPtr != (VmCOWInfo *)NIL) {
  157.     free((Address)cowInfoPtr);
  158.     }
  159.     DoFork(srcSegPtr, destSegPtr);
  160. }
  161.  
  162.  
  163. /*
  164.  *----------------------------------------------------------------------
  165.  *
  166.  * DoFork --
  167.  *
  168.  *    Make the dest segment copy-on-reference off of the src segment.
  169.  *
  170.  * Results:
  171.  *    None.
  172.  *
  173.  * Side effects:
  174.  *    Source and destination page tables modified to set up things
  175.  *    as copy-on-write and copy-on-reference.  Also number of COW and COR
  176.  *    pages in each segment is modified.
  177.  *
  178.  *----------------------------------------------------------------------
  179.  */
  180. static void
  181. DoFork(srcSegPtr, destSegPtr)
  182.     register    Vm_Segment    *srcSegPtr;
  183.     register    Vm_Segment    *destSegPtr;
  184. {    
  185.     register    Vm_PTE    *destPTEPtr;
  186.     register    Vm_PTE    *srcPTEPtr;
  187.     register    int    virtPage;
  188.     register    int    lastPage;
  189.     register    int    numCORPages = 0;
  190.     register    int    numCOWPages = 0;
  191.     register    Vm_PTE    corPTE;
  192.     Vm_VirtAddr        virtAddr;
  193.     VmCOWInfo        *cowInfoPtr;
  194.  
  195.     LOCK_MONITOR;
  196.  
  197.     corPTE = VM_VIRT_RES_BIT | VM_COR_BIT | srcSegPtr->segNum;
  198.  
  199.     if (srcSegPtr->type == VM_HEAP) {
  200.     virtPage = srcSegPtr->offset;
  201.     lastPage = virtPage + srcSegPtr->numPages - 1;
  202.     srcPTEPtr = srcSegPtr->ptPtr;
  203.     destPTEPtr = destSegPtr->ptPtr;
  204.     } else {
  205.     virtPage = mach_LastUserStackPage - srcSegPtr->numPages + 1;
  206.     lastPage = mach_LastUserStackPage;
  207.     srcPTEPtr = VmGetPTEPtr(srcSegPtr, virtPage);
  208.     destPTEPtr = VmGetPTEPtr(destSegPtr, virtPage);
  209.     }
  210.  
  211.     virtAddr.segPtr = srcSegPtr;
  212.     virtAddr.flags = 0;
  213.     virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  214.     for (; virtPage <= lastPage;
  215.      virtPage++, VmIncPTEPtr(srcPTEPtr, 1), VmIncPTEPtr(destPTEPtr, 1)) {
  216.     if (!(*srcPTEPtr & VM_VIRT_RES_BIT)) {
  217.         *destPTEPtr = 0;
  218.         continue;
  219.     }
  220.     while (*srcPTEPtr & VM_IN_PROGRESS_BIT) {
  221.         (void)Sync_Wait(&srcSegPtr->condition, FALSE);
  222.     }
  223.     if (*srcPTEPtr & VM_COW_BIT) {
  224.         /*
  225.          * This page is already copy-on-write.  Make child copy-on-ref
  226.          * off of the parent segment.
  227.          */
  228.         *destPTEPtr = corPTE;
  229.         numCORPages++;
  230.     } else if (*srcPTEPtr & VM_COR_BIT) {
  231.         /*
  232.          * This page is already copy-on-reference.  Make the child be
  233.          * copy-on-ref on the same segment.
  234.          */
  235.         *destPTEPtr = *srcPTEPtr;
  236.         numCORPages++;
  237.     } else if (*srcPTEPtr & (VM_PHYS_RES_BIT | VM_ON_SWAP_BIT)) {
  238.         /*
  239.          * Need to make the src copy-on-write and the dest copy-on-ref.
  240.          */
  241.         *srcPTEPtr |= VM_COW_BIT;
  242.         if (*srcPTEPtr & VM_PHYS_RES_BIT) {
  243.         virtAddr.page = virtPage;
  244.         virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  245.         VmMach_SetPageProt(&virtAddr, *srcPTEPtr);
  246.         }
  247.         numCOWPages++;
  248.         *destPTEPtr = corPTE;
  249.         numCORPages++;
  250.     } else {
  251.         /*
  252.          * Just a normal everyday pte (zerofill or load from FS).
  253.          */
  254.         *destPTEPtr = *srcPTEPtr;
  255.     }
  256.     }
  257.  
  258.     cowInfoPtr = srcSegPtr->cowInfoPtr;
  259.     if (numCORPages > 0) {
  260.     if (srcSegPtr->type == VM_HEAP) {
  261.         vmStat.numCOWHeapPages += numCOWPages;
  262.         vmStat.numCORHeapPages += numCORPages;
  263.     } else {
  264.         vmStat.numCOWStkPages += numCOWPages;
  265.         vmStat.numCORStkPages += numCORPages;
  266.     }
  267.     srcSegPtr->numCOWPages += numCOWPages;
  268.     destSegPtr->numCORPages = numCORPages;
  269.     /*
  270.      * Insert the child into the COW list for the parent segment.
  271.      */
  272.     destSegPtr->cowInfoPtr = cowInfoPtr;
  273.     List_Insert((List_Links *)destSegPtr, 
  274.             LIST_ATREAR(&cowInfoPtr->cowList));
  275.     cowInfoPtr->numSegs++;
  276.     }
  277.     cowInfoPtr->copyInProgress = 0;
  278.     Sync_Broadcast(&cowInfoPtr->condition);
  279.  
  280.     UNLOCK_MONITOR;
  281. }
  282.  
  283.  
  284. /*
  285.  *----------------------------------------------------------------------
  286.  *
  287.  * VmCOWCopySeg --
  288.  *
  289.  *    Make a copy of the given segment.  This includes handling all
  290.  *    copy-on-write and copy-on-reference pages.  This segment will
  291.  *    be removed from its copy-on-write chain.  It is assumed that the
  292.  *    calling segment has the in-use count of its page tables incremented.
  293.  *
  294.  * Results:
  295.  *    None.
  296.  *
  297.  * Side effects:
  298.  *    Memory for a COW info struct may be freed.
  299.  *
  300.  *----------------------------------------------------------------------
  301.  */
  302. ReturnStatus
  303. VmCOWCopySeg(segPtr)
  304.     register    Vm_Segment    *segPtr;
  305. {
  306.     register    Vm_PTE        *ptePtr;
  307.     VmCOWInfo            *cowInfoPtr;
  308.     Vm_VirtAddr            virtAddr;
  309.     int                firstPage;
  310.     int                lastPage;
  311.     ReturnStatus        status = SUCCESS;
  312.  
  313.     cowInfoPtr = (VmCOWInfo *)NIL;
  314.     if (!COWStart(segPtr, &cowInfoPtr)) {
  315.     return(SUCCESS);
  316.     }
  317.     if (segPtr->type == VM_STACK) {
  318.     firstPage = mach_LastUserStackPage - segPtr->numPages + 1;
  319.     } else {
  320.     firstPage = segPtr->offset;
  321.     }
  322.     lastPage = firstPage + segPtr->numPages - 1;
  323.     virtAddr.segPtr = segPtr;
  324.     virtAddr.flags = 0;
  325.     virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  326.     for (virtAddr.page = firstPage, ptePtr = VmGetPTEPtr(segPtr, firstPage);
  327.      virtAddr.page <= lastPage;
  328.      virtAddr.page++, VmIncPTEPtr(ptePtr, 1)) {
  329.     if (*ptePtr & VM_COW_BIT) {
  330.         COW(&virtAddr, ptePtr, IsResident(ptePtr), FALSE);
  331.         VmPageValidate(&virtAddr);
  332.     } else if (*ptePtr & VM_COR_BIT) {
  333.         status = COR(&virtAddr, ptePtr);
  334.         if (status != SUCCESS) {
  335.         break;
  336.         }
  337.     }
  338.     }
  339.  
  340.     cowInfoPtr = (VmCOWInfo *)NIL;
  341.     COWEnd(segPtr, &cowInfoPtr);
  342.     if (cowInfoPtr != (VmCOWInfo *)NIL) {
  343.     free((Address)cowInfoPtr);
  344.     }
  345.     return(status);
  346. }
  347.  
  348.  
  349. /*
  350.  *----------------------------------------------------------------------
  351.  *
  352.  * VmCOWDeleteFromSeg --
  353.  *
  354.  *    Invalidate all cow or cor pages from the given range of pages in
  355.  *    the given segment.  It is assumed that this routine is called with
  356.  *    the segment's page tables in use count incremented.
  357.  *
  358.  * Results:
  359.  *    None.
  360.  *
  361.  * Side effects:
  362.  *    All cow or cor pages in the given range of pages are invalidated.
  363.  *
  364.  *----------------------------------------------------------------------
  365.  */
  366. void
  367. VmCOWDeleteFromSeg(segPtr, firstPage, lastPage)
  368.     register    Vm_Segment    *segPtr;
  369.     register    int        firstPage;    /* First page to delete. -1
  370.                          * if want the lowest possible
  371.                          * page. */
  372.     register    int        lastPage;    /* Last page to delete. -1
  373.                          * if want the highest possible
  374.                          * page. */
  375. {
  376.     register    Vm_PTE        *ptePtr;
  377.     VmCOWInfo            *cowInfoPtr;
  378.     Vm_VirtAddr            virtAddr;
  379.  
  380.     if (firstPage == -1) {
  381.     /*
  382.      * Caller wants to invalidate all pages for this segment.  This
  383.      * is only done when the segment is deleted.
  384.      */
  385.     if (segPtr->type == VM_STACK) {
  386.         firstPage = mach_LastUserStackPage - segPtr->numPages + 1;
  387.     } else {
  388.         firstPage = segPtr->offset;
  389.     }
  390.     lastPage = firstPage + segPtr->numPages - 1;
  391.     }
  392.     cowInfoPtr = (VmCOWInfo *)NIL;
  393.     if (!COWStart(segPtr, &cowInfoPtr)) {
  394.     return;
  395.     }
  396.     virtAddr.segPtr = segPtr;
  397.     virtAddr.flags = 0;
  398.     virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  399.     for (ptePtr = VmGetPTEPtr(segPtr, firstPage);
  400.      firstPage <= lastPage;
  401.      firstPage++, VmIncPTEPtr(ptePtr, 1)) {
  402.     if (*ptePtr & VM_COW_BIT) {
  403.         virtAddr.page = firstPage;
  404.         COW(&virtAddr, ptePtr, IsResident(ptePtr), TRUE);
  405.     } else if (*ptePtr & VM_COR_BIT) {
  406.         segPtr->numCORPages--;
  407.         if (segPtr->numCORPages < 0) {
  408.         panic("VmCOWDeleteFromSeg: numCORPages < 0\n");
  409.         }
  410.     }
  411.     }
  412.  
  413.     cowInfoPtr = (VmCOWInfo *)NIL;
  414.     COWEnd(segPtr, &cowInfoPtr);
  415.     if (cowInfoPtr != (VmCOWInfo *)NIL) {
  416.     free((Address)cowInfoPtr);
  417.     }
  418. }
  419.  
  420.  
  421. /*
  422.  *----------------------------------------------------------------------
  423.  *
  424.  * COWStart --
  425.  *
  426.  *    Mark the segment as copy-on-write in progress.  After this routine
  427.  *    is called all future copy-on-writes are blocked until released
  428.  *    by a call to COWEnd.
  429.  *
  430.  * Results:
  431.  *    If the segment is not currently involved in a copy-on-write chain and
  432.  *    *cowInfoPtrPtr is NIL then this routine returns FALSE.  Otherwise
  433.  *    it returns TRUE.
  434.  *
  435.  * Side effects:
  436.  *    Copy-in-progress flag is set.  Also if there is no copy-on-write
  437.  *    chain yet and *cowInfoPtrPtr is not equal to NIL, then a new
  438.  *    one is created and *cowInfoPtrPtr is set to NIL.
  439.  *
  440.  *----------------------------------------------------------------------
  441.  */
  442. static Boolean
  443. COWStart(segPtr, cowInfoPtrPtr)
  444.     register    Vm_Segment    *segPtr;    /* Segment to begin COW for.*/
  445.     register    VmCOWInfo    **cowInfoPtrPtr;/* Pointer to pointer to
  446.                          * COW info struct that can
  447.                          * be used if no struct yet
  448.                          * exists. */ 
  449. {
  450.     register    VmCOWInfo    *cowInfoPtr;
  451.  
  452.     LOCK_MONITOR;
  453.  
  454. again:
  455.  
  456.     if (segPtr->cowInfoPtr == (VmCOWInfo *)NIL) {
  457.     cowInfoPtr = *cowInfoPtrPtr;
  458.     if (cowInfoPtr == (VmCOWInfo *)NIL) {
  459.         UNLOCK_MONITOR;
  460.         return(FALSE);
  461.     }
  462.     segPtr->cowInfoPtr = cowInfoPtr;
  463.     cowInfoPtr->copyInProgress = TRUE;
  464.     List_Init(&cowInfoPtr->cowList);
  465.     List_Insert((List_Links *)segPtr, LIST_ATREAR(&cowInfoPtr->cowList));
  466.     cowInfoPtr->numSegs = 1;
  467.     *cowInfoPtrPtr = (VmCOWInfo *)NIL;
  468.     } else {
  469.     cowInfoPtr = segPtr->cowInfoPtr;
  470.     if (cowInfoPtr->copyInProgress) {
  471.         (void)Sync_Wait(&cowInfoPtr->condition, FALSE);
  472.         goto again;
  473.     } else {
  474.         cowInfoPtr->copyInProgress = TRUE;
  475.     }
  476.     }
  477.  
  478.     UNLOCK_MONITOR;
  479.     return(TRUE);
  480. }
  481.  
  482.  
  483. /*
  484.  *----------------------------------------------------------------------
  485.  *
  486.  * COWEnd --
  487.  *
  488.  *    Clean up after a copy-on-write or copy-on-ref has happened.
  489.  *
  490.  * Results:
  491.  *    None.
  492.  *
  493.  * Side effects:
  494.  *    *cowInfoPtrPtr is set to point to COW info struct to free if there
  495.  *    are no segments left COW.
  496.  *
  497.  *----------------------------------------------------------------------
  498.  */
  499. static void
  500. COWEnd(segPtr, cowInfoPtrPtr)
  501.     register    Vm_Segment    *segPtr;     /* Segment that was involved
  502.                           * in the COW or COR. */
  503.     VmCOWInfo            **cowInfoPtrPtr; /* Set to point to a COW
  504.                           * info struct to free. */
  505. {
  506.     register    VmCOWInfo    *cowInfoPtr;
  507.  
  508.  
  509.     LOCK_MONITOR;
  510.  
  511.     cowInfoPtr = segPtr->cowInfoPtr;
  512.     cowInfoPtr->copyInProgress = FALSE;
  513.     Sync_Broadcast(&cowInfoPtr->condition);
  514.     if (segPtr->numCOWPages == 0 && segPtr->numCORPages == 0) {
  515.     List_Remove((List_Links *)segPtr);
  516.     segPtr->cowInfoPtr = (VmCOWInfo *)NIL;
  517.     cowInfoPtr->numSegs--;
  518.     }
  519.     if (cowInfoPtr->numSegs == 0) {
  520.     *cowInfoPtrPtr = cowInfoPtr;
  521.     } else if (cowInfoPtr->numSegs == 1) {
  522.     register Vm_Segment    *cowSegPtr;
  523.     register Vm_PTE        *ptePtr;
  524.     int            firstPage;
  525.     int            lastPage;
  526.     register int        i;
  527.     /*
  528.      * Only one segment left.  Return this segment back to normal
  529.      * protection and clean up.
  530.      */
  531.     *cowInfoPtrPtr = cowInfoPtr;
  532.     cowSegPtr = (Vm_Segment *)List_First(&cowInfoPtr->cowList);
  533.     cowSegPtr->cowInfoPtr = (VmCOWInfo *)NIL;
  534.     if (cowSegPtr->type == VM_STACK) {
  535.         firstPage = mach_LastUserStackPage - cowSegPtr->numPages + 1;
  536.     } else {
  537.         firstPage = cowSegPtr->offset;
  538.     }
  539.     lastPage = firstPage + cowSegPtr->numPages - 1;
  540.     for (ptePtr = VmGetPTEPtr(cowSegPtr, firstPage),
  541.         i = cowSegPtr->numPages;
  542.          i > 0;
  543.          i--, VmIncPTEPtr(ptePtr, 1)) {
  544.         *ptePtr &= ~(VM_COW_BIT | VM_COR_BIT);
  545.     }
  546.     VmMach_SetSegProt(cowSegPtr, firstPage, lastPage, TRUE);
  547.     cowSegPtr->numCORPages = 0;
  548.     cowSegPtr->numCOWPages = 0;
  549.     }
  550.  
  551.     UNLOCK_MONITOR;
  552. }
  553.  
  554.  
  555. /*
  556.  *----------------------------------------------------------------------
  557.  *
  558.  * FindNewMasterSeg --
  559.  *
  560.  *    Find a segment that is sharing the given page copy-on-reference.
  561.  *
  562.  * Results:
  563.  *    Pointer to segment that is sharing the given page copy-on-reference.
  564.  *
  565.  * Side effects:
  566.  *    All segments that are now dependent on the new master have their page
  567.  *    table entries set to point to the new master segment.
  568.  *
  569.  *----------------------------------------------------------------------
  570.  */
  571. static Vm_Segment *
  572. FindNewMasterSeg(segPtr, page, othersPtr)
  573.     register    Vm_Segment    *segPtr;    /* Current master. */
  574.     int                page;        /* Virtual page. */
  575.     Boolean            *othersPtr;    /* Set to TRUE if there are
  576.                          * other COW children. */
  577. {
  578.     register    List_Links    *cowList;
  579.     register    Vm_Segment    *newSegPtr;
  580.     register    Vm_PTE        *ptePtr;
  581.     Vm_Segment            *mastSegPtr = (Vm_Segment *)NIL;
  582.  
  583.     *othersPtr = FALSE;
  584.     cowList = &segPtr->cowInfoPtr->cowList;
  585.     newSegPtr = (Vm_Segment *)List_Next((List_Links  *)segPtr);
  586.     while (!List_IsAtEnd(cowList, (List_Links *)newSegPtr)) {
  587.     /*
  588.      * Make sure the page exists in this segment, then check the PTE.
  589.      */
  590.     if (page - newSegPtr->offset < newSegPtr->ptSize) {
  591.         ptePtr = VmGetPTEPtr(newSegPtr, page);
  592.         if ((*ptePtr & VM_COR_BIT) &&
  593.         Vm_GetPageFrame(*ptePtr) == segPtr->segNum) {
  594.         if (mastSegPtr != (Vm_Segment *)NIL) {
  595.             *ptePtr &= ~VM_PAGE_FRAME_FIELD;
  596.             *ptePtr |= mastSegPtr->segNum;
  597.             *othersPtr = TRUE;
  598.         } else {
  599.             mastSegPtr = newSegPtr;
  600.         }
  601.         }
  602.     }
  603.     newSegPtr = (Vm_Segment *)List_Next((List_Links  *)newSegPtr);
  604.     }
  605.     return(mastSegPtr);
  606. }
  607.  
  608.  
  609. /*
  610.  *----------------------------------------------------------------------
  611.  *
  612.  * IsResident --
  613.  *
  614.  *    Determine if the page is resident in the given page table entry.
  615.  *
  616.  * Results:
  617.  *    TRUE if the page is resident. 
  618.  *
  619.  * Side effects:
  620.  *    Page locked down if resident.
  621.  *
  622.  *----------------------------------------------------------------------
  623.  */
  624. static Boolean
  625. IsResident(ptePtr)
  626.     Vm_PTE    *ptePtr;
  627. {
  628.     Boolean    retVal;
  629.  
  630.     LOCK_MONITOR;
  631.  
  632.     if (*ptePtr & VM_PHYS_RES_BIT) {
  633.     VmLockPageInt(Vm_GetPageFrame(*ptePtr));
  634.     retVal = TRUE;
  635.     } else {
  636.     retVal = FALSE;
  637.     }
  638.  
  639.     UNLOCK_MONITOR;
  640.  
  641.     return(retVal);
  642. }
  643.  
  644.  
  645. /*
  646.  *----------------------------------------------------------------------
  647.  *
  648.  * VmCOR --
  649.  *
  650.  *    Handle a copy-on-reference fault.  If the virtual address is not
  651.  *    truly COR then don't do anything.  It is assumed that the given
  652.  *    segment's page tables have had their in-use count incremented.
  653.  *
  654.  * Results:
  655.  *    Status from VmPageServerRead if had to read from swap space.  
  656.  *    Otherwise SUCCESS.
  657.  *
  658.  * Side effects:
  659.  *    Page table for current segment is modified.
  660.  *
  661.  *----------------------------------------------------------------------
  662.  */
  663. ReturnStatus
  664. VmCOR(virtAddrPtr)
  665.     register    Vm_VirtAddr    *virtAddrPtr;
  666. {
  667.     register    Vm_PTE        *ptePtr;
  668.     VmCOWInfo            *cowInfoPtr;
  669.     ReturnStatus        status;
  670.  
  671.     if (virtAddrPtr->segPtr->type == VM_HEAP) {
  672.     vmStat.numCORHeapFaults++;
  673.     } else {
  674.     vmStat.numCORStkFaults++;
  675.     }
  676.     cowInfoPtr = (VmCOWInfo *)NIL;
  677.     if (!COWStart(virtAddrPtr->segPtr, &cowInfoPtr)) {
  678.     vmStat.quickCORFaults++;
  679.     return(SUCCESS);
  680.     }
  681.     ptePtr = VmGetAddrPTEPtr(virtAddrPtr, virtAddrPtr->page);
  682.     if (!(*ptePtr & VM_COR_BIT)) {
  683.     vmStat.quickCORFaults++;
  684.     status = SUCCESS;
  685.     } else {
  686.     status = COR(virtAddrPtr, ptePtr);
  687.     }
  688.  
  689.     cowInfoPtr = (VmCOWInfo *)NIL;
  690.     COWEnd(virtAddrPtr->segPtr, &cowInfoPtr);
  691.     if (cowInfoPtr != (VmCOWInfo *)NIL) {
  692.     free((Address)cowInfoPtr);
  693.     }
  694.  
  695.     return(status);
  696. }
  697.  
  698.  
  699. /*
  700.  *----------------------------------------------------------------------
  701.  *
  702.  * COR --
  703.  *
  704.  *    Handle a copy-on-reference fault.
  705.  *
  706.  * Results:
  707.  *    Status from VmPageServerRead if had to read from swap space.  
  708.  *    Otherwise SUCCESS.
  709.  *
  710.  * Side effects:
  711.  *    Page table for current segment is modified.
  712.  *
  713.  *----------------------------------------------------------------------
  714.  */
  715. static ReturnStatus
  716. COR(virtAddrPtr, ptePtr)
  717.     register    Vm_VirtAddr    *virtAddrPtr;
  718.     register    Vm_PTE        *ptePtr;
  719. {
  720.     register    Vm_Segment    *mastSegPtr;
  721.     unsigned    int        virtFrameNum;
  722.     unsigned    int        mastVirtPF;
  723.     ReturnStatus        status;
  724.     int                corCheckBit;
  725.  
  726.     mastSegPtr = VmGetSegPtr((int) (Vm_GetPageFrame(*ptePtr)));
  727.     virtFrameNum = VmPageAllocate(virtAddrPtr, VM_CAN_BLOCK);
  728.     mastVirtPF = GetMasterPF(mastSegPtr, virtAddrPtr->page);
  729.     if (mastVirtPF != 0) {
  730.     /*
  731.      * The page is resident in memory so copy it.
  732.      */
  733.     CopyPage(mastVirtPF, virtFrameNum);
  734.     VmUnlockPage(mastVirtPF);
  735.     } else {
  736.     /*
  737.      * Load the page off of swap space.
  738.      */
  739.     Vm_VirtAddr    virtAddr;
  740.  
  741.     virtAddr.segPtr = mastSegPtr;
  742.     virtAddr.page = virtAddrPtr->page;
  743.     virtAddr.flags = 0;
  744.     virtAddr.sharedPtr = virtAddrPtr->sharedPtr;
  745.     status = VmPageServerRead(&virtAddr, virtFrameNum);
  746.     if (status != SUCCESS) {
  747.         printf("Warning: VmCOR: Couldn't read page, status <%x>\n", status);
  748.         VmPageFree(virtFrameNum);
  749.         return(status);
  750.     }
  751.     }
  752.  
  753.     virtAddrPtr->segPtr->numCORPages--;
  754.     if (virtAddrPtr->segPtr->numCORPages < 0) {
  755.     panic("COR: numCORPages < 0\n");
  756.     }
  757.     if (vmCORReadOnly) {
  758.     corCheckBit = VM_COR_CHECK_BIT | VM_READ_ONLY_PROT;
  759.     } else {
  760.     corCheckBit = 0;
  761.     }
  762.  
  763.     SetPTE(virtAddrPtr, (Vm_PTE)(VM_VIRT_RES_BIT | VM_PHYS_RES_BIT | 
  764.              VM_REFERENCED_BIT | VM_MODIFIED_BIT | corCheckBit |
  765.              virtFrameNum));
  766.     VmUnlockPage(virtFrameNum);
  767.     SeeIfLastCOR(mastSegPtr, virtAddrPtr->page);
  768.     return(SUCCESS);
  769. }
  770.  
  771.  
  772. /*
  773.  *----------------------------------------------------------------------
  774.  *
  775.  * GetMasterPF --
  776.  *
  777.  *    Return the page frame from the master segment's page table
  778.  *    entry.  0 if the page is not resident.
  779.  *
  780.  * Results:
  781.  *    The page frame from the masters PTE.  0 if not resident.
  782.  *    Otherwise SUCCESS.
  783.  *
  784.  * Side effects:
  785.  *    Page frame returned locked if resident.
  786.  *
  787.  *----------------------------------------------------------------------
  788.  */
  789. static unsigned int
  790. GetMasterPF(mastSegPtr, virtPage)
  791.     Vm_Segment    *mastSegPtr;
  792.     int        virtPage;
  793. {
  794.     unsigned    int    pf;
  795.     register    Vm_PTE    *mastPTEPtr;
  796.  
  797.     LOCK_MONITOR;
  798.  
  799.     mastPTEPtr = VmGetPTEPtr(mastSegPtr, virtPage);
  800.     if (*mastPTEPtr & VM_PHYS_RES_BIT) {
  801.     pf = Vm_GetPageFrame(*mastPTEPtr);
  802.     VmLockPageInt(pf);
  803.     } else {
  804.     pf = 0;
  805.     }
  806.  
  807.     UNLOCK_MONITOR;
  808.  
  809.     return(pf);
  810. }
  811.  
  812.  
  813. /*
  814.  *----------------------------------------------------------------------
  815.  *
  816.  * SeeIfLastCOR --
  817.  *
  818.  *    See if there are any more segments that are COR off of the given 
  819.  *    page in the given segment.
  820.  *
  821.  * Results:
  822.  *    None.
  823.  *
  824.  * Side effects:
  825.  *    If there are no other pages COR of the given page in the given segment
  826.  *    then the page is made no longer COW.
  827.  *
  828.  *----------------------------------------------------------------------
  829.  */
  830. static void
  831. SeeIfLastCOR(mastSegPtr, page)
  832.     register    Vm_Segment    *mastSegPtr;
  833.     int                page;
  834. {
  835.     register    List_Links    *cowList;
  836.     register    Vm_Segment    *childSegPtr;
  837.     register    Vm_PTE        *ptePtr;
  838.     Vm_VirtAddr            virtAddr;
  839.  
  840.     LOCK_MONITOR;
  841.  
  842.     cowList = &mastSegPtr->cowInfoPtr->cowList;
  843.     childSegPtr = (Vm_Segment *)List_Next((List_Links *)mastSegPtr);
  844.     while (!List_IsAtEnd(cowList, (List_Links *)childSegPtr)) {
  845.     /*
  846.      * Make sure the page exists in this segment, then check the PTE.
  847.      */
  848.     if (page - childSegPtr->offset < childSegPtr->ptSize) {
  849.         ptePtr = VmGetPTEPtr(childSegPtr, page);
  850.         if ((*ptePtr & VM_COR_BIT) &&
  851.         Vm_GetPageFrame(*ptePtr) == mastSegPtr->segNum) {
  852.         UNLOCK_MONITOR;
  853.         return;
  854.         }
  855.     }
  856.     childSegPtr = (Vm_Segment *)List_Next((List_Links *)childSegPtr);
  857.     }
  858.  
  859.     /*
  860.      * No more pages are COR off of the master.  Make the page no longer
  861.      * copy-on-write.
  862.      */
  863.     ptePtr = VmGetPTEPtr(mastSegPtr, page);
  864.     *ptePtr &= ~VM_COW_BIT;
  865.     mastSegPtr->numCOWPages--;
  866.     if (mastSegPtr->numCOWPages == 0 && mastSegPtr->numCORPages == 0) {
  867.     /*
  868.      * If there are no more COW or COR pages then remove ourselves
  869.      * from the list.  We know that we are only called by the routine
  870.      * COR() which means that there is guaranteed to be at least one
  871.      * segment left in the list.  Therefore there is no need to worry
  872.      * about freeing up the cow info struct.
  873.      */
  874.     List_Remove((List_Links *)mastSegPtr);
  875.     mastSegPtr->cowInfoPtr->numSegs--;
  876.     mastSegPtr->cowInfoPtr = (VmCOWInfo *)NIL;
  877.     }
  878.     if (*ptePtr & VM_PHYS_RES_BIT) {
  879.     virtAddr.segPtr = mastSegPtr;
  880.     virtAddr.page = page;
  881.     virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  882.     VmMach_SetPageProt(&virtAddr, *ptePtr);
  883.     }
  884.  
  885.     UNLOCK_MONITOR;
  886. }
  887.  
  888.  
  889. /*
  890.  *----------------------------------------------------------------------
  891.  *
  892.  * VmCOW --
  893.  *
  894.  *    Handle a copy-on-write fault.  If the current virtual address is
  895.  *    not truly COW then we don't do anything.
  896.  *
  897.  * Results:
  898.  *    None.
  899.  *
  900.  * Side effects:
  901.  *    Page table for the given virtual address is modified and the page
  902.  *    table of the new master (if any) is modified.
  903.  *
  904.  *----------------------------------------------------------------------
  905.  */
  906. void
  907. VmCOW(virtAddrPtr)
  908.     register    Vm_VirtAddr    *virtAddrPtr;
  909. {
  910.     register    Vm_PTE        *ptePtr;
  911.     VmCOWInfo            *cowInfoPtr;
  912.  
  913.     if (virtAddrPtr->segPtr->type == VM_HEAP) {
  914.     vmStat.numCOWHeapFaults++;
  915.     } else {
  916.     vmStat.numCOWStkFaults++;
  917.     }
  918.     cowInfoPtr = (VmCOWInfo *)NIL;
  919.     if (!COWStart(virtAddrPtr->segPtr, &cowInfoPtr)) {
  920.     vmStat.quickCOWFaults++;
  921.     return;
  922.     }
  923.     ptePtr = VmGetAddrPTEPtr(virtAddrPtr, virtAddrPtr->page);
  924.     if (!(*ptePtr & VM_COW_BIT)) {
  925.     vmStat.quickCOWFaults++;
  926.     } else if (IsResident(ptePtr)) {
  927.     COW(virtAddrPtr, ptePtr, TRUE, FALSE);
  928.     }
  929.  
  930.     cowInfoPtr = (VmCOWInfo *)NIL;
  931.     COWEnd(virtAddrPtr->segPtr, &cowInfoPtr);
  932.     if (cowInfoPtr != (VmCOWInfo *)NIL) {
  933.     free((Address)cowInfoPtr);
  934.     }
  935. }
  936.  
  937.  
  938. /*
  939.  *----------------------------------------------------------------------
  940.  *
  941.  * COW --
  942.  *
  943.  *    Handle a copy-on-write fault.
  944.  *
  945.  * Results:
  946.  *    None.
  947.  *
  948.  * Side effects:
  949.  *    None.
  950.  *
  951.  *----------------------------------------------------------------------
  952.  */
  953. static void
  954. COW(virtAddrPtr, ptePtr, isResident, deletePage)
  955.     register    Vm_VirtAddr    *virtAddrPtr;    /* Virtual address to copy.*/
  956.     register    Vm_PTE        *ptePtr;    /* Pointer to the page table
  957.                          * entry. */
  958.     Boolean            isResident;    /* TRUE => The page is resident
  959.                          *       in memory and locked
  960.                          *       down. */
  961.     Boolean            deletePage;    /* TRUE => Delete the page
  962.                          *         after copying. */
  963. {
  964.     register    Vm_Segment    *mastSegPtr;
  965.     Vm_VirtAddr            virtAddr;
  966.     Boolean            others;
  967.     unsigned int        virtFrameNum;
  968.     Vm_PTE            pte;
  969.  
  970.     mastSegPtr = FindNewMasterSeg(virtAddrPtr->segPtr, virtAddrPtr->page,
  971.                   &others);
  972.     if (mastSegPtr != (Vm_Segment *)NIL) {
  973.     mastSegPtr->numCORPages--;
  974.     if (mastSegPtr->numCORPages < 0) {
  975.         panic("COW: numCORPages < 0\n");
  976.     }
  977.     if (others) {
  978.         mastSegPtr->numCOWPages++;
  979.     }
  980.     virtAddr.segPtr = mastSegPtr;
  981.     virtAddr.page = virtAddrPtr->page;
  982.     virtAddr.flags = 0;
  983.     virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  984.     if (isResident) {
  985.         /*
  986.          * The page is resident and locked down by our caller. 
  987.          */
  988.         if (deletePage) {
  989.         /*
  990.          * This page is being invalidated. In this case just give
  991.          * away the page, no need to copy it.
  992.          */
  993.         GiveAwayPage(virtAddrPtr->segPtr, virtAddrPtr->page, ptePtr,
  994.                  mastSegPtr, others);
  995.         } else {
  996.         /*
  997.          * Copy the page.
  998.          */
  999.         virtFrameNum = VmPageAllocate(&virtAddr, VM_CAN_BLOCK);
  1000.         CopyPage(Vm_GetPageFrame(*ptePtr), virtFrameNum);
  1001.         pte = VM_VIRT_RES_BIT | VM_PHYS_RES_BIT | 
  1002.               VM_REFERENCED_BIT | VM_MODIFIED_BIT | virtFrameNum;
  1003.         if (others) {
  1004.             pte |= VM_COW_BIT;
  1005.         }
  1006.         SetPTE(&virtAddr, pte);
  1007.         VmUnlockPage(virtFrameNum);
  1008.         VmUnlockPage(Vm_GetPageFrame(*ptePtr));
  1009.         }
  1010.     } else {
  1011.         /*
  1012.          * The page is on swap space.
  1013.          */
  1014.         (void)VmCopySwapPage(virtAddrPtr->segPtr, 
  1015.                 virtAddrPtr->page, mastSegPtr);
  1016.         pte = VM_VIRT_RES_BIT | VM_ON_SWAP_BIT;
  1017.         if (others) {
  1018.         pte |= VM_COW_BIT;
  1019.         }
  1020.         SetPTE(&virtAddr, pte);
  1021.     }
  1022.     if (mastSegPtr->numCOWPages == 0 && mastSegPtr->numCORPages == 0) {
  1023.         mastSegPtr->cowInfoPtr->numSegs--;
  1024.         List_Remove((List_Links *)mastSegPtr);
  1025.         mastSegPtr->cowInfoPtr = (VmCOWInfo *)NIL;
  1026.     }
  1027.     } else {
  1028.     vmStat.quickCOWFaults++;
  1029.     }
  1030.  
  1031.     /*
  1032.      * Change from copy-on-write back to normal if it has not already been
  1033.      * done by some other routine.
  1034.      */
  1035.     if (*ptePtr & VM_COW_BIT) {
  1036.     ReleaseCOW(ptePtr);
  1037.     }
  1038.     virtAddrPtr->segPtr->numCOWPages--;
  1039.     if (virtAddrPtr->segPtr->numCOWPages < 0) {
  1040.     panic("COW: numCOWPages < 0\n");
  1041.     }
  1042. }
  1043.  
  1044.  
  1045.  
  1046. /*
  1047.  *----------------------------------------------------------------------
  1048.  *
  1049.  * GiveAwayPage --
  1050.  *
  1051.  *    Transfer a page from one segment to another.
  1052.  *
  1053.  * Results:
  1054.  *    None.
  1055.  *
  1056.  * Side effects:
  1057.  *    Source segments page table has the page zapped and the
  1058.  *    destination page table takes over ownership of the page.
  1059.  *
  1060.  *----------------------------------------------------------------------
  1061.  */
  1062. static void
  1063. GiveAwayPage(srcSegPtr, virtPage, srcPTEPtr, destSegPtr, others)
  1064.     register    Vm_Segment    *srcSegPtr;    /* Segment to take page from.*/
  1065.     int                virtPage;    /* Virtual page to give away.*/
  1066.     register    Vm_PTE        *srcPTEPtr;    /* PTE for the segment to take
  1067.                          * the page away from. */
  1068.     register    Vm_Segment    *destSegPtr;    /* Segment to give page to. */
  1069.     Boolean            others;        /* TRUE => other segments that
  1070.                          * are copy-on-write on 
  1071.                          * the destination segment. */
  1072. {
  1073.     Vm_VirtAddr        virtAddr;
  1074.     register    Vm_PTE    *destPTEPtr;
  1075.     unsigned    int    pageFrame;
  1076.     Boolean        referenced;
  1077.     Boolean        modified;
  1078.  
  1079.     LOCK_MONITOR;
  1080.  
  1081.     srcSegPtr->resPages--;
  1082.     destSegPtr->resPages++;
  1083.     virtAddr.segPtr = srcSegPtr;
  1084.     virtAddr.page = virtPage;
  1085.     virtAddr.flags = 0;
  1086.     virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  1087.     pageFrame = Vm_GetPageFrame(*srcPTEPtr);
  1088.     destPTEPtr = VmGetPTEPtr(destSegPtr, virtPage);
  1089.     *destPTEPtr = *srcPTEPtr & ~VM_COW_BIT;
  1090.     *srcPTEPtr = 0;
  1091.     VmMach_GetRefModBits(&virtAddr, pageFrame, &referenced, &modified);
  1092.     if (referenced) {
  1093.     *destPTEPtr |= VM_REFERENCED_BIT;
  1094.     }
  1095.     if (modified) {
  1096.     *destPTEPtr |= VM_MODIFIED_BIT;
  1097.     }
  1098.     VmMach_PageInvalidate(&virtAddr, pageFrame, FALSE);
  1099.     if (others) {
  1100.     *destPTEPtr |= VM_COW_BIT;
  1101.     }
  1102.     VmPageSwitch(Vm_GetPageFrame(*destPTEPtr), destSegPtr);
  1103.     UNLOCK_MONITOR;
  1104. }
  1105.  
  1106. /*
  1107.  *----------------------------------------------------------------------
  1108.  *
  1109.  * SetPTE --
  1110.  *
  1111.  *    Set the given pte at the given virtual address.
  1112.  *
  1113.  * Results:
  1114.  *    None.
  1115.  *
  1116.  * Side effects:
  1117.  *    None.
  1118.  *
  1119.  *----------------------------------------------------------------------
  1120.  */
  1121. static void
  1122. SetPTE(virtAddrPtr, pte)
  1123.     Vm_VirtAddr    *virtAddrPtr;
  1124.     Vm_PTE    pte;
  1125. {
  1126.     Vm_PTE    *ptePtr;
  1127.  
  1128.     LOCK_MONITOR;
  1129.  
  1130.     ptePtr = VmGetAddrPTEPtr(virtAddrPtr, virtAddrPtr->page);
  1131.     *ptePtr = pte;
  1132.     if (pte & VM_PHYS_RES_BIT) {
  1133.     virtAddrPtr->segPtr->resPages++;
  1134.     }
  1135.  
  1136.     UNLOCK_MONITOR;
  1137. }
  1138.  
  1139.  
  1140. /*
  1141.  *----------------------------------------------------------------------
  1142.  *
  1143.  * CopyPage --
  1144.  *
  1145.  *    Copy the given page frame to the given destination.
  1146.  *
  1147.  * Results:
  1148.  *    None.
  1149.  *
  1150.  * Side effects:
  1151.  *    None.
  1152.  *
  1153.  *----------------------------------------------------------------------
  1154.  */
  1155. static void
  1156. CopyPage(srcPF, destPF)
  1157.     unsigned    int    srcPF;
  1158.     unsigned    int    destPF;
  1159. {
  1160.     register    Address    srcMappedAddr;
  1161.     register    Address    destMappedAddr;
  1162.  
  1163.     srcMappedAddr = VmMapPage(srcPF);
  1164.     destMappedAddr = VmMapPage(destPF);
  1165.     bcopy(srcMappedAddr, destMappedAddr, vm_PageSize);
  1166.     VmUnmapPage(srcMappedAddr);
  1167.     VmUnmapPage(destMappedAddr);
  1168. }
  1169.  
  1170.  
  1171. /*
  1172.  *----------------------------------------------------------------------
  1173.  *
  1174.  * ReleaseCOW --
  1175.  *
  1176.  *    Make the page no longer copy-on-write.
  1177.  *
  1178.  * Results:
  1179.  *    None.
  1180.  *
  1181.  * Side effects:
  1182.  *    None.
  1183.  *
  1184.  *----------------------------------------------------------------------
  1185.  */
  1186. static void
  1187. ReleaseCOW(ptePtr)
  1188.     Vm_PTE    *ptePtr;
  1189. {
  1190.     LOCK_MONITOR;
  1191.  
  1192.     *ptePtr &= ~VM_COW_BIT;
  1193.  
  1194.     UNLOCK_MONITOR;
  1195. }
  1196.